package com.xy.biz.xd.service.impl;

import com.xy.biz.xd.domain.bo.DocumentFlowBO;
import com.xy.biz.xd.domain.bo.DocumentFlowCancelRequestFlowBO;
import com.xy.biz.xd.domain.bo.DocumentFlowHandleBO;
import com.xy.biz.xd.domain.query.DocumentFlowHandleQuery;
import com.xy.biz.xd.manager.DocumentFlowHandleManager;
import com.xy.tool.context.UserContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;

import static com.xy.biz.xd.domain.bo.DocumentFlowConstants.*;

@Slf4j
@Service
public class DocumentFlowServiceSupport {

    @Autowired
    private DocumentFlowHandleManager documentFlowHandleManager;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;

    public DocumentFlowHandleBO getDocumentFlowHandleBO(DocumentFlowBO documentFlowBO, String phase) {
        List<DocumentFlowHandleBO> documentFlowHandleBOList = documentFlowHandleManager.listDocumentFlowHandle(
                DocumentFlowHandleQuery.max()
                        .documentFlowId(documentFlowBO.getDocumentFlowId())
                        .phase(phase)
                        .build());
        if (!CollectionUtils.isEmpty(documentFlowHandleBOList)) {
            return documentFlowHandleBOList.get(0);
        }
        return null;
    }

    public List<DocumentFlowHandleBO> listDocumentFlowHandleBO(DocumentFlowBO documentFlowBO, String phase) {
        return documentFlowHandleManager.listDocumentFlowHandle(
                DocumentFlowHandleQuery.max()
                        .documentFlowId(documentFlowBO.getDocumentFlowId())
                        .phase(phase)
                        .build());
    }

    public void updateCurrentDocumentFlowHandleBO(DocumentFlowBO documentFlowBO, String phase, int result,
                                                  String opinion, LocalDateTime updateTime) {
        DocumentFlowHandleBO currentDocumentFlowHandleBO = getCurrentDocumentFlowHandleBO(documentFlowBO, phase);
        currentDocumentFlowHandleBO.setResult(result);
        currentDocumentFlowHandleBO.setOpinion(opinion);
        currentDocumentFlowHandleBO.setUpdateTime(updateTime);
        documentFlowHandleManager.updateDocumentFlowHandle(currentDocumentFlowHandleBO);
    }

    public DocumentFlowHandleBO getCurrentDocumentFlowHandleBO(DocumentFlowBO documentFlowBO, String phase) {
        List<DocumentFlowHandleBO> documentFlowHandleBOList = documentFlowHandleManager.listDocumentFlowHandle(
                DocumentFlowHandleQuery.one()
                        .documentFlowId(documentFlowBO.getDocumentFlowId())
                        .phase(phase)
                        .handleUserId(UserContextHolder.getUserId())
                        .build());
        if (!CollectionUtils.isEmpty(documentFlowHandleBOList)) {
            return documentFlowHandleBOList.get(0);
        }
        return null;
    }

    public Long getEditor(DocumentFlowBO documentFlowBO, String phase) {
        List<DocumentFlowHandleBO> documentFlowHandleBOList = documentFlowHandleManager.listDocumentFlowHandle(
                DocumentFlowHandleQuery.one()
                        .documentFlowId(documentFlowBO.getDocumentFlowId())
                        .phase(phase)
                        .build());
        if (!CollectionUtils.isEmpty(documentFlowHandleBOList)) {
            return documentFlowHandleBOList.get(0).getHandleUserId();
        }
        return null;
    }

    public Task startFirstTask(DocumentFlowBO documentFlowBO, String processDefinitionKey, Long assignee) {
        Map<String, Object> variables = new HashMap<>();
        variables.put(VARIABLE_ASSIGNEE, assignee);
        variables.put(VARIABLE_HANDLE, String.valueOf(HANDLE_RESULT_ACCEPT));
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey,
                documentFlowBO.getDocumentFlowId().toString(), variables);
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstance.getProcessInstanceId())
                .singleResult();
        taskService.complete(task.getId());
        return task;
    }

    public Task startFirstTaskOfCancelRequest(DocumentFlowCancelRequestFlowBO documentFlowCancelRequestFlowBO, String processDefinitionKey, Long assignee) {
        Map<String, Object> variables = new HashMap<>();
        variables.put(VARIABLE_ASSIGNEE, assignee);
        variables.put(VARIABLE_HANDLE, String.valueOf(HANDLE_RESULT_ACCEPT));
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey,
                documentFlowCancelRequestFlowBO.getCancelRequestFlowId().toString(), variables);
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstance.getProcessInstanceId())
                .singleResult();
        taskService.complete(task.getId());
        return task;
    }
    /*
     *//**
     * 撤回
     *//*
    public void recall(DocumentFlowBO documentFlowBO, String phase) {
        //获取当前任务
        Task currentTask = getCurrentTask(documentFlowBO);
        //获取历史处理任务实例
        List<HistoricTaskInstance> htlist = historyService.createHistoricTaskInstanceQuery()
                //.processDefinitionId(currentTask.getProcessDefinitionId())
                .executionId(currentTask.getExecutionId())
                .list();
        String myTaskId = null;
        HistoricTaskInstance myTask = null;
        for (HistoricTaskInstance hti : htlist) {
            //要回退的目的节点名
            if (hti.getTaskDefinitionKey().equals(phase)) {
                myTaskId = hti.getId();
                myTask = hti;
                break;
            }
        }
        if (myTask == null) {
            throw new RuntimeException("无此节点");
        }
        String processDefinitionId = myTask.getProcessDefinitionId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        String myActivityId = null;
        //获取历史活动实例
        List<HistoricActivityInstance> haiList =
                historyService
                        .createHistoricActivityInstanceQuery()
                        .executionId(myTask.getExecutionId())
                        .finished()
                        .list();

        for (HistoricActivityInstance hai : haiList) {
            if(myTaskId.equals(hai.getTaskId())) {
                myActivityId = hai.getActivityId();
                break;
            }
        }
        FlowNode myFlowNode =
                (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId);
        Execution execution = runtimeService.createExecutionQuery()
                .executionId(currentTask.getExecutionId()).singleResult();
        String activityId = execution.getActivityId();
        System.out.println(activityId);
        FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess()
                .getFlowElement(activityId);
        //记录原活动方向
        List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
        oriSequenceFlows.addAll(flowNode.getOutgoingFlows());
        //清理活动方向
        flowNode.getOutgoingFlows().clear();
        //建立新方向
        List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(flowNode);
        newSequenceFlow.setTargetFlowElement(myFlowNode);
        newSequenceFlowList.add(newSequenceFlow);
        flowNode.setOutgoingFlows(newSequenceFlowList);
        Authentication.setAuthenticatedUserId(UserContextHolder.getUserId()+"");
        //完成任务
        taskService.complete(currentTask.getId());
        //恢复原方向
        flowNode.setOutgoingFlows(oriSequenceFlows);
    }*/

    /**
     * 终止
     */
    public void finish(DocumentFlowBO documentFlowBO) {
        Task task = getCancelTask(documentFlowBO);
        if (task != null) {
            Map<String, Object> variables = new HashMap<>();
            variables.put(VARIABLE_HANDLE, String.valueOf(HANDLE_RESULT_END));
            taskService.complete(task.getId(), variables);
        } else {
            log.error("文档流程" + documentFlowBO.getDocumentFlowId() + "没有任务");
        }
    }

    public Task finishLastTask(DocumentFlowBO documentFlowBO) {
        Task task = getCurrentTask(documentFlowBO);
        if (task != null) {
            Map<String, Object> variables = new HashMap<>();
            variables.put(VARIABLE_HANDLE, String.valueOf(HANDLE_RESULT_ACCEPT));
            taskService.complete(task.getId(), variables);
        } else {
            log.error("文档流程" + documentFlowBO.getDocumentFlowId() + "没有任务");
        }
        return task;
    }

    public Task finishLastTaskOfCancelRequest(DocumentFlowCancelRequestFlowBO documentFlowCancelRequestFlowBO) {
        Task task = getCurrentTask(documentFlowCancelRequestFlowBO);
        if (task != null) {
            Map<String, Object> variables = new HashMap<>();
            variables.put(VARIABLE_HANDLE, String.valueOf(HANDLE_RESULT_ACCEPT));
            taskService.complete(task.getId(), variables);
        } else {
            log.error("文档流程" + documentFlowCancelRequestFlowBO.getCancelRequestFlowId() + "没有任务");
        }
        return task;
    }

    public Task getCurrentTask(DocumentFlowBO documentFlowBO) {
        return taskService.createTaskQuery()
                .taskAssignee(UserContextHolder.getUserId().toString())
                .processInstanceId(documentFlowBO.getForeignKey())
                .singleResult();
    }

    public Task getCancelTask(DocumentFlowBO documentFlowBO) {
        return taskService.createTaskQuery()
                .processInstanceId(documentFlowBO.getForeignKey())
                .singleResult();
    }

    public Task getCurrentTask(DocumentFlowCancelRequestFlowBO documentFlowCancelRequestFlowBO) {
        return taskService.createTaskQuery()
                .taskAssignee(UserContextHolder.getUserId().toString())
                .processInstanceId(documentFlowCancelRequestFlowBO.getForeignKey())
                .singleResult();
    }

    public void gotoNextTask(DocumentFlowBO documentFlowBO, Long assignee, int result) {
        Task task = getCurrentTask(documentFlowBO);
        if (task != null) {
            gotoNextTask(task, assignee, result);
        } else {
            log.error("文档流程" + documentFlowBO.getDocumentFlowId() + "没有任务");
        }
    }

    public void gotoNextTask(Task task, Long assignee, int result) {
        if (task != null) {
            Map<String, Object> variables = new HashMap<>();
            variables.put(VARIABLE_ASSIGNEE, assignee);
            variables.put(VARIABLE_HANDLE, String.valueOf(result));

            taskService.complete(task.getId(), variables);
        } else {
            log.error("文档流程没有任务");
        }
    }

    public void gotoNextTask2(DocumentFlowBO documentFlowBO, List<Long> assigneeList, int result) {
        Task task = getCurrentTask(documentFlowBO);
        if (task != null) {
            gotoNextTask2(task, assigneeList, result);
        } else {
            log.error("文档流程" + documentFlowBO.getDocumentFlowId() + "没有任务");
        }
    }

    public void gotoNextTask2(Task task, List<Long> assigneeList, int result) {
        if (task != null) {
            Map<String, Object> variables = new HashMap<>();
            variables.put(VARIABLE_ASSIGNEE_LIST, assigneeList);
            variables.put(VARIABLE_HANDLE, String.valueOf(result));

            taskService.complete(task.getId(), variables);
        } else {
            log.error("文档流程没有任务");
        }
    }

    public int getHandleCountForPhase(DocumentFlowBO documentFlowBO, String phase) {
        int count = documentFlowHandleManager.countDocumentFlowHandle(
                DocumentFlowHandleQuery.max()
                        .documentFlowId(documentFlowBO.getDocumentFlowId())
                        .phase(phase)
                        .build());
        return count;
    }

    public int getHandleCountForPhaseAndResult(DocumentFlowBO documentFlowBO, String phase, int result) {
        int count = documentFlowHandleManager.countDocumentFlowHandle(
                DocumentFlowHandleQuery.max()
                        .documentFlowId(documentFlowBO.getDocumentFlowId())
                        .phase(phase)
                        .result(result)
                        .build());
        return count;
    }

    public DocumentFlowHandleBO getLastPhaseHandleUser(DocumentFlowBO documentFlowBO, String phase) {
        DocumentFlowHandleBO documentFlowHandleBO = documentFlowHandleManager.getLastPhaseHandle(
                DocumentFlowHandleQuery.builder()
                        .documentFlowId(documentFlowBO.getDocumentFlowId())
                        .phase(phase)
                        .build());
        if (Objects.isNull(documentFlowHandleBO)) {
            throw new RuntimeException("找不到上一个节点处理人！");
        }
        return documentFlowHandleBO;

    }
}
